﻿using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

using xEngine.Input;
using xEngine.Rendering;

namespace xEngine.UI.Screens
{
    public abstract class Screen
    {
        #region Member Variables

        private xEngine.Input.InputManager __input;
        protected float __alpha;
        private float __fadeLeft;
        private Keys? __skipBtn;
        private float __elapsed;

        #endregion

        #region Properties

        protected xEngine.Input.InputManager Input { get { return __input; } }
        public ScreenManager ScreenManager { get; protected set; }

        public bool Initialized { get; private set; }

        public ScreenState State { get; protected set; }

        public bool Active { get; protected set; }
        public bool UpdateWhileInactive { get; set; }

        protected float FadeTimeout { get; set; }

        protected bool ProcessMouse { get; set; }
        protected bool ProcessKeyboard { get; set; }

        #endregion

        #region Constructors

        public Screen(Keys? skipBtn)
        {
            __alpha = 1.0f;
            FadeTimeout = 0.5f;
            ProcessKeyboard = ProcessMouse = true;
            State = ScreenState.Normal;
            __skipBtn = skipBtn;
        }

        #endregion

        #region Functions

        protected virtual void OnMouseDown(object sender, MouseButtonEventArgs e) { }
        protected virtual void OnMouseUp(object sender, MouseButtonEventArgs e) { }
        protected virtual void OnMouseMoved(object sender, MouseMovedEventArgs e) { }
        protected virtual void OnMouseWheel(object sender, MouseWheelEventArgs e) { }

        public virtual void Initialize(ScreenManager manager)
        {
            if (manager == null)
                return;

            ScreenManager = manager;

            // Input System
            __input = new xEngine.Input.InputManager(new Point(ScreenManager.GraphicsDevice.Viewport.Width / 2, ScreenManager.GraphicsDevice.Viewport.Height / 2));
            __input.MouseMoved += new EventHandler<MouseMovedEventArgs>(OnMouseMoved);
            __input.MouseWheel += new EventHandler<MouseWheelEventArgs>(OnMouseWheel);
            __input.MouseDown += new EventHandler<MouseButtonEventArgs>(OnMouseDown);
            __input.MouseUp += new EventHandler<MouseButtonEventArgs>(OnMouseUp);

            __fadeLeft = FadeTimeout;

            if (__skipBtn.HasValue)
                Input.AddKeyEventHandler(__skipBtn.Value, delegate { if (__elapsed > 0.2f) FadeOut(); });

            Initialized = true;
        }

        public virtual void LoadContent() { }
        public virtual void UnloadContent() { }

        public virtual void Render(GameTime gameTime)
        {
            ScreenManager.SpriteBatch.Begin();
            ScreenManager.SpriteBatch.Draw(GenericResources.BlankTexture, new Rectangle(0, 0, ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height), Color.Black * __alpha);
            ScreenManager.SpriteBatch.End();
        }

        public void ProcessTransition(GameTime gameTime)
        {
            __fadeLeft -= (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (__fadeLeft <= 0)
            {
                if (State == ScreenState.FadeIn)
                {
                    __alpha = 0.0f;
                    Active = true;
                    State = ScreenState.Normal;
                }

                else if (State == ScreenState.FadeOut)
                {
                    __alpha = 1.0f;
                    Active = false;
                    State = ScreenState.Normal;
                    UnloadContent();
                    ScreenManager.ActiveScreen++;
                }
            }

            if (State == ScreenState.FadeIn)
                __alpha -= (float)gameTime.ElapsedGameTime.TotalSeconds / FadeTimeout;
            else if (State == ScreenState.FadeOut)
                __alpha += (float)gameTime.ElapsedGameTime.TotalSeconds / FadeTimeout;
        }

        public virtual void Update(GameTime gameTime)
        {
            // Do not process if not active
            if (Active)
            {
                __elapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (ProcessKeyboard)
                    __input.ProcessKeyboard();

                if (ProcessMouse)
                    __input.ProcessMouse();
            }
        }

        public virtual void FadeOut()
        {
            if (State == ScreenState.FadeOut)
                return;
                        
            __fadeLeft = FadeTimeout;
            State = ScreenState.FadeOut;
        }
        public virtual void FadeIn()
        {
            if (State == ScreenState.FadeIn)
                return;

            Active = true;
            __fadeLeft = FadeTimeout;
            State = ScreenState.FadeIn;
        }

        #endregion
    }

    public enum ScreenState
    {
        FadeIn,
        FadeOut,
        Normal
    }
}
